package util;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Arrays;
/**
 * DataPackage
 * Structure of the messages send and received by/from the Station
 * 
 * @author Jan Quenzel
 * @author Rico Flaegel
 */
public class DataPackage {
	/**
	 * length of a DataPackage
	 */
	public final static int len = 33;
	/**
	 * real time where package was send
	 */
	private long time;
	/**
	 * Slot number in next Frame
	 */
	private byte nextSlotNumber;
	/**
	 * data which should be transfered with this message/package 
	 */
	private byte[] data;
	
	/**
	 * constructs the bytearray containing the bytesequence of the DataPackage
	 * @return bytearray containing the bytesequence of the DataPackage
	 */
	public byte[] toByte(){
		ByteBuffer bb = ByteBuffer.allocate(len);
		ByteBuffer blong = ByteBuffer.allocate(8);
		blong.putLong(getTime());
		blong.order(ByteOrder.BIG_ENDIAN); // make big endian byte order for the number
		for(int i = 0; i < 8; i++)
			bb.put(25+i,blong.get(i));
		bb.put(24, getNextSlotNumber());
		byte[] dat = getData();
		for(int i = 0; i < 24 && i < dat.length; i++){
			bb.put(i,dat[i]);
		}
		return bb.array();
	}
	
	/**
	 * restore information from a bytesequence representing the DataPackage
	 * @param b the bytesequence which should be restored
	 */
	public void fromByte(byte [] b){
		ByteBuffer bb = ByteBuffer.allocate(len);
		bb.put(b);
		setNextSlotNumber(bb.get(24));
		ByteBuffer blong = ByteBuffer.allocate(8);
		for(int i = 0; i < 8; i++)
			blong.put(i,bb.get(25+i));
		setTime(blong.getLong());
		//string noch machen
		byte[] st = new byte[24];
		for(int i = 0; i < st.length; i++){
			st[i] = b[i];
		}
		setData(st);
	}
	/**
	 * construct a byte array from a long
	 * @param l the long which should be converted to a long 
	 * @return byte array
	 */
	public static byte[] longToByte(long l){
		ByteBuffer bb = ByteBuffer.allocate(8);
		bb.putLong(l);
		return bb.array();
	}
	/**
	 * Construct a Long value from a array of bytes
	 * @param b byte array containing a long value
	 * @param pos position where to start inside the array
	 * @return the long value
	 */
	public static long byteToLong(byte[] b, int pos){
		ByteBuffer bb = ByteBuffer.allocate(8);
		bb.put(b, pos, 8);
		return bb.getLong();
	}
	/**
	 * Change the endianness of a byte array to little or big endian.
	 * @param b the byte array
	 * @param little true if little endian wanted
	 * @return the byte array in wanted endianess 
	 */
	public static byte[] changeEndianess(byte[] b,boolean little){
		ByteBuffer bb = ByteBuffer.allocate(b.length);
		bb.put(b);
		bb.order((little?ByteOrder.LITTLE_ENDIAN:ByteOrder.BIG_ENDIAN));
		return bb.array();
	}
	
	public String toString(){
		return "'"+new String(getData())+"' ("+getTime()+", next slot: "+getNextSlotNumber()+")";
	}
	/**
	 * get length of a DataPackage
	 * @return len
	 */
	public int getByteLength() {
		return len;
	}
	/**
	 * Gives the transported data.
	 * For the DataPackage in byte use toByte(). 
	 * @return contained data
	 */
	public byte[] getData() {
		return data;
	}
	/**
	 * Sets the transported data.
	 * @param data which should be transported
	 */
	public void setData(byte[] data) {
		this.data = data;
	}

	/**
	 * Number of next Slot.
	 * @return number of next slot.
	 */
	public byte getNextSlotNumber() {
		return nextSlotNumber;
	}
	/**
	 * set the number of the next slot.
	 * @param nextslotnumber number in next slot.
	 */
	public void setNextSlotNumber(byte nextslotnumber) {
		this.nextSlotNumber = nextslotnumber;
	}
	/**
	 * Get the send time of the package.
	 * @return the time where it was send.
	 */
	public long getTime() {
		return time;
	}
	/**
	 * Set the send time of the package.
	 * @param time the time where it is send.
	 */
	public void setTime(long time) {
		this.time = time;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj ) return true; 
		if(obj != null && this.getClass() == obj.getClass()){
			DataPackage other = (DataPackage) obj;
			return Arrays.equals(this.toByte(),other.toByte());
		}
		return false;
	}
	
}
